package com.jyw.system.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.jyw.common.constant.ConfigKeyConstant;
import com.jyw.common.utils.DateUtils;
import com.jyw.common.utils.SecurityUtils;
import com.jyw.system.domain.SysFileInfo;
import com.jyw.system.domain.vo.MinioConfigVO;
import com.jyw.system.domain.vo.SimpleFileVo;
import com.jyw.system.mapper.SysFileInfoMapper;
import com.jyw.system.service.ISysConfigService;
import com.jyw.system.service.ISysFileInfoService;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统附件Service业务层处理
 *
 * @author system
 * @date 2023-08-17
 */
@Service
@Slf4j
public class SysFileInfoServiceImpl extends ServiceImpl<SysFileInfoMapper, SysFileInfo> implements ISysFileInfoService {

    @Resource
    private ISysConfigService configService;

    private String bucket;

    @Override
    public List<SimpleFileVo> upload(MultipartFile... files) {
        MinioClient minioClient = getMinioClient();
        String folders = getFolders();
        List<SysFileInfo> fileInfoList = Lists.newArrayList();
        for (MultipartFile file : files) {
            // UUID重命名
            String fileName = UUID.fastUUID().toString(true) + "." + FileUtil.getSuffix(file.getOriginalFilename());
            String filePath = StrUtil.format("{}{}", folders, fileName);
            InputStream fi = null;
            try {
                fi = file.getInputStream();
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .stream(fi, file.getSize(), PutObjectArgs.MIN_MULTIPART_SIZE)
                                .object(filePath)
                                .contentType(file.getContentType())
                                .bucket(this.bucket)
                                .build()
                );
            } catch (Exception e) {
                log.error("上传文件失败", e);
                continue;
            } finally {
                if (!ObjectUtils.isEmpty(fi)) {
                    try {
                        fi.close();
                    } catch (IOException e) {
                        log.error("关闭文件流失败", e);
                    }
                }
            }
            //封装数据库实体
            SysFileInfo fileInfo = new SysFileInfo();
            fileInfo.setUrl(filePath);
            fileInfo.setName(file.getOriginalFilename());
            fileInfo.setCreateUser(SecurityUtils.getUserId());
            fileInfo.setCreateTime(DateUtils.getNowDate());
            fileInfoList.add(fileInfo);
        }
        //保存数据库
        saveBatch(fileInfoList);
        //返回响应对象
        return fileInfoList.stream().map(data -> data.toSimple()).collect(Collectors.toList());
    }

    @Override
    public String previewFile(String url) throws Exception {
        MinioClient minioClient = getMinioClient();
        GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs
                .builder().bucket(bucket).object(url).method(Method.GET).build();
        return minioClient.getPresignedObjectUrl(build);
    }

    @Override
    public InputStream download(String url) throws Exception {
        MinioClient minioClient = getMinioClient();
        InputStream stream = minioClient.getObject(
                GetObjectArgs.builder().bucket(bucket).object(url).build());
        return stream;
    }

    @Override
    public String uploadReturnUrl(File file) throws Exception {
        MinioClient minioClient = getMinioClient();
        String folders = getFolders();
        // UUID重命名
        String fileName = UUID.fastUUID().toString(true) + "." + FileUtil.getSuffix(file.getName());
        String filePath = StrUtil.format("{}{}", folders, fileName);
        InputStream fi = null;
        String contentType = Files.probeContentType(file.toPath());
        if(ObjectUtils.isEmpty(contentType)){
            //如果contentType为空,那么设置contentType为voice/speex 微信录音需要
            contentType = "voice/speex";
        }
        try {
            fi = new FileInputStream(file);
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .stream(fi, fi.available(), PutObjectArgs.MIN_MULTIPART_SIZE)
                            .object(filePath)
                            .contentType(contentType)
                            .bucket(this.bucket)
                            .build()
            );
            return filePath;
        } catch (Exception e) {
            log.error("上传文件失败", e);
        } finally {
            if (!ObjectUtils.isEmpty(fi)) {
                try {
                    fi.close();
                } catch (IOException e) {
                    log.error("关闭文件流失败", e);
                }
            }
        }
        return null;
    }

    @Override
    public SimpleFileVo upload(File file) throws Exception {

        MinioClient minioClient = getMinioClient();
        String folders = getFolders();
        // UUID重命名
        String fileName = UUID.fastUUID().toString(true) + "." + FileUtil.getSuffix(file.getName());
        String filePath = StrUtil.format("{}{}", folders, fileName);
        InputStream fi = null;
        try {
            fi = new FileInputStream(file);
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .stream(fi, fi.available(), PutObjectArgs.MIN_MULTIPART_SIZE)
                            .object(filePath)
                            .contentType(Files.probeContentType(file.toPath()))
                            .bucket(this.bucket)
                            .build()
            );

            SysFileInfo fileInfo = new SysFileInfo();
            fileInfo.setUrl(filePath);
            fileInfo.setName(file.getName());
            fileInfo.setCreateUser(SecurityUtils.getUserId());
            fileInfo.setCreateTime(DateUtils.getNowDate());
            save(fileInfo);
            return fileInfo.toSimple();
        } catch (Exception e) {
            log.error("上传文件失败", e);
        } finally {
            if (!ObjectUtils.isEmpty(fi)) {
                try {
                    fi.close();
                } catch (IOException e) {
                    log.error("关闭文件流失败", e);
                }
            }
        }
        return null;
    }

    @Override
    public String saveFileUrl(String urlPath, String contentType, String suffix) throws IOException {
        log.info("-----开始从" + urlPath + " 下载文件");
        MinioClient minioClient = getMinioClient();
        InputStream inputStream = HttpUtil.createGet(urlPath).execute().bodyStream();

        String folders = getFolders();
        // UUID重命名
        String fileName = UUID.fastUUID().toString(true) + "." + suffix;
        String filePath = StrUtil.format("{}{}", folders, fileName);

        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        if(StringUtils.isEmpty(contentType)) {
            contentType = fileNameMap.getContentTypeFor(urlPath);
        }
        log.info("-----" + urlPath + " 下载成功");
        try {
            log.info("-----往minio服务器存入");
            minioClient.putObject(PutObjectArgs.builder()
                    .stream(inputStream, inputStream.available(), PutObjectArgs.MIN_MULTIPART_SIZE)
                    .object(filePath)
                    .bucket(this.bucket)
                    .contentType(contentType)
                    .build());
            log.info("-----往minio服务器存入成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return filePath;
    }


    private String getFolders() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(StrUtil.format("yyyy/MM/dd/")));
    }

    public MinioClient getMinioClient() {
        MinioConfigVO config = JSONObject.parse(configService.selectConfigByKey(ConfigKeyConstant.MINIO_CONFIG)).toJavaObject(MinioConfigVO.class);
        this.bucket = config.getBucket();
        return MinioClient.builder().endpoint(config.getEndpoint()).credentials(config.getAccessKey(), config.getSecretKey()).build();
    }

}
